package com.github.live.manager;

import android.text.TextUtils;
import android.util.ArrayMap;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.live.base.LiveApplication;
import com.github.live.player.MultiPlayerFactory;
import com.github.live.util.ChannelWrapper;
import com.github.live.util.LogFactory;
import com.github.live.util.SourceWrapper;
import com.github.livebase.bean.Channel;
import com.github.livebase.bean.ChannelGroup;
import com.github.livebase.util.LiveContext;
import com.github.livebase.util.base.ArraysUtil;
import com.github.livebase.util.base.Assert;
import com.github.livebase.util.base.CollectionsUtil;
import com.github.livebase.util.base.IOUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

import xyz.doikki.videoplayer.ijk.IjkIMediaPlayerFactory;
import xyz.doikki.videoplayer.player.VideoViewConfig;
import xyz.doikki.videoplayer.player.VideoViewManager;
import xyz.doikki.videoplayer.render.TextureRenderViewFactory;

/**
 * @ClassName LiveInitializer
 * @description:
 * @author: biao532
 * @create: 2024-02-02 09:37
 * @Version 1.0
 **/
public class LiveInitializer {
    private boolean init;
    private LiveContext mContext;
    private EpgManager epgManager;
    private ChannelsManager channelsManager;
    private LiveConfig config;
    private SettingManager settingManager;
    private static volatile LiveInitializer initializer;
    public static LiveInitializer getInitializer() {
        if (initializer == null) {
            synchronized (LiveInitializer.class) {
                if (null == initializer) {
                    initializer = new LiveInitializer();
                }
            }
        }
        return initializer;
    }
    private LiveInitializer() {
        this.init = false;
        this.mContext = LiveApplication.getContext();
        // 无需动态初始化
        this.epgManager = new EpgManager(this.mContext);
    }

    public void init() {
        LogFactory.debug(LiveInitializer.class, "LiveInitializer.init {}", "start");
        this.init = true;
        config = readConfig();

        VideoViewManager.setConfig(new VideoViewConfig.Builder()
                .setPlayerFactory(new MultiPlayerFactory(config.getIjkM_maxCount(), new IjkIMediaPlayerFactory()))
                .setRenderViewFactory(new TextureRenderViewFactory()).build());

        if (channelsManager != null) {
            channelsManager.unregister();
        }
        List<ChannelGroup> group = mContext.getPluginFactory().getGroups();
        initGroup(group);
        channelsManager = new ChannelsManager(group);

        settingManager = new SettingManager(mContext, mContext.getPluginFactory().getIjkCodec());
        LogFactory.debug(LiveInitializer.class, "LiveInitializer.init {}", "end");
    }

    public ChannelsManager getChannelsManager() {
        checkInit();
        return channelsManager;
    }

    public LiveConfig getConfig() {
        checkInit();
        return config;
    }

    public EpgManager getEpgManager() {
        checkInit();
        return epgManager;
    }

    public SettingManager getSettingManager() {
        checkInit();
        return settingManager;
    }

    private LiveConfig readConfig() {
        File config = new File(LiveApplication.getContext().getExternalFilesDir(""), "liveConfig.properties");
        Properties properties = new Properties();
        if(config.exists()) {
            try(InputStream stream = new FileInputStream(config)) {
                properties.load(stream);
                LogFactory.info(LiveInitializer.class,"从 {} 中读取配置成功", config.getAbsolutePath());
            } catch (IOException e) {
                LogFactory.info(LiveInitializer.class,
                        String.format("从 %s 中读取配置失败", config.getAbsolutePath()),
                        e);
            }
        }
        return new LiveConfig(properties);
    }
    private void checkInit() {
        Assert.isTrue(init, "Not initialized, please invoke method[init] first");
    }

    private List<ChannelGroup> initGroup(List<ChannelGroup> groups) {
        // 全局配置项组
        List<ChannelGroup> cgl = CollectionsUtil.filter(groups, (g) -> {
            return "".equals(g.getName()) && CollectionsUtil.isEmpty(g.getChannels());
        });
        Map<String, String> configMap = new ArrayMap<>();
        CollectionsUtil.foreach(cgl, (g) -> configMap.putAll(g.getOpt()));

        // 处理同id引用
        Map<String, Channel> channelMap = new ArrayMap<>();
        // 合并所有相同id的数据
        CollectionsUtil.foreach(groups, (g) -> {
            CollectionsUtil.foreach(g.getChannels(), (c)-> {
                channelMerge(channelMap, c);
            });
        });

        // 根据id，重设为合并的数据项
        CollectionsUtil.foreach(groups, (g) -> {
            CollectionsUtil.foreach(g.getChannels(), (c)-> {
                copyTo(channelMap.get(c.getId()), c);
            });
        });

        // 过滤无效数据
        filterGroup(groups);

        // 重设logo 和 number
        Map<String, String> iconMap = getIcons();
        AtomicInteger i = new AtomicInteger(1);
        CollectionsUtil.foreach(groups, (g) -> {
            CollectionsUtil.foreach(g.getChannels(), (c)-> {
                if (!getConfig().isSupportCustomNumber()) {
                    c.setNumber(i.getAndIncrement());
                }
                if (TextUtils.isEmpty(c.getLogo())) {
                    c.setLogo(iconMap.get(c.getName()));
                }
            });
        });
        // 转化为Wrapper
        convertWrapper(groups, configMap);
        return groups;
    }

    private void copyTo(Channel from, Channel to) {
        to.setSources(from.getSources());
        to.setName(getOrDefault(to.getName(), from.getName()));
        to.setLogo(getOrDefault(to.getLogo(), from.getLogo()));
        to.setOpt(from.getOpt());
    }
    private void channelMerge(Map<String, Channel> channelMap, Channel channel) {
        // 不存在直接塞入
        if (!channelMap.containsKey(channel.getId())) {
            channelMap.put(channel.getId(), channel);
            return;
        }

        // 合并opt
        Channel c = channelMap.get(channel.getId());
        Map<String, String> opt = c.getOpt();
        if (opt == null || opt.isEmpty()) {
            c.setOpt(channel.getOpt());
        }
        else {
            if (channel.getOpt() != null) {
                opt.putAll(channel.getOpt());
            }
        }

        // 合并source
        List<Channel.Source> sources = c.getSources();
        List<String> urls = CollectionsUtil.convert(sources, s -> s.getLive());
        // 筛选不存在的source
        List<Channel.Source> list = CollectionsUtil.filter(channel.getSources(), (s)-> {
            return !urls.contains(s.getLive());
        });

        if (CollectionsUtil.isEmpty(sources)) {
            c.setSources(channel.getSources());
        }
        else {
            if (list != null) {
                sources.addAll(list);
            }
        }

        // 设置属性
        c.setLogo(getOrDefault(c.getLogo(), channel.getLogo()));
        c.setName(getOrDefault(c.getName(), channel.getName()));
    }
    private String getOrDefault(String val, String def) {
        if (TextUtils.isEmpty(val)) {
            return def;
        }
        return val;
    }
    private Map<String, String> getIcons() {
        String str = null;
        try(InputStream stream = this.mContext.getAssets().open("epg_data.json")){
            str = IOUtil.toString(stream);
        } catch (IOException e) {
            return new ArrayMap<>(0);
        }
        Map<String, String> map = new ArrayMap<>();
        try {
            JSONArray array = JSONObject.parseArray(str);
            for (int i = 0; i < array.size(); i++) {
                JSONObject obj = array.getJSONObject(i);
                String[] names = obj.getString("name").split(",");
                String icon = obj.getString("logo");
                ArraysUtil.foreach(names, (n)-> {
                    map.put(n, icon);
                });
            }
        } catch (Exception e) {
        }
        return map;
    }
    private void filterGroup(List<ChannelGroup> groups) {
        if (CollectionsUtil.isEmpty(groups)) {
            return ;
        }
        Iterator<ChannelGroup> i = groups.iterator();
        int idx = 1;
        while (i.hasNext()) {
            ChannelGroup g = i.next();
            filterChannel(g, idx);
            if (g == null || CollectionsUtil.isEmpty(g.getChannels())) {
                i.remove();
                continue;
            }
            if (TextUtils.isEmpty(g.getName())) {
                g.setName("未命名" + idx++);
            }
        }
    }

    private void filterChannel(ChannelGroup group, int groupIndex) {
        if (group == null || CollectionsUtil.isEmpty(group.getChannels())) {
            return ;
        }
        Iterator<Channel> i = group.getChannels().iterator();
        LiveConfig liveConfig = getConfig();
        int idx = 1;
        while (i.hasNext()) {
            Channel s = i.next();
            if (liveConfig.isSupportCustomNumber() && s.getNumber() <= 0) {
                i.remove();
                continue;
            }
            filterSource(s);
            if (s == null || CollectionsUtil.isEmpty(s.getSources()) || TextUtils.isEmpty(s.getId())) {
                i.remove();
                continue;
            }
            if (TextUtils.isEmpty(s.getName())) {
                s.setName("频道"+groupIndex + "-" + idx++);
            }
        }
    }

    private void filterSource(Channel channel) {
        if (channel == null || CollectionsUtil.isEmpty(channel.getSources())) {
            return;
        }
        LiveConfig liveConfig = getConfig();
        Iterator<Channel.Source> i = channel.getSources().iterator();
        int idx = 1;
        while (i.hasNext()) {
            Channel.Source s = i.next();
            if (s == null || TextUtils.isEmpty(s.getLive())) {
                i.remove();
                continue;
            }
            // 分辨率过滤
            if (s.getResolution() > liveConfig.getSupportedResolution()) {
                i.remove();
                continue;
            }
            if (TextUtils.isEmpty(s.getLive())) {
                s.setName("源" + idx++);
            }
        }
    }

    private void convertWrapper(List<ChannelGroup> groups, Map<String, String> option) {
        for (ChannelGroup group : groups) {
            for (Channel channel : group.getChannels()) {
                List<Channel.Source> wrappers = CollectionsUtil.convert(channel.getSources(), (s) -> {
                    return new SourceWrapper(option, group, channel, s);
                });
                channel.setSources(wrappers);
            }
            List<Channel> channels = CollectionsUtil.convert(group.getChannels(), (c) -> {
                return new ChannelWrapper(option, group, c);
            });
            group.setChannels(channels);
        }

    }
}
